package com.ydm.myapp001.bean;

import android.app.Activity;;
import android.util.Log;

import com.google.gson.Gson;
import com.ydm.myapp001.utils.AppLogger;

import java.io.IOException;
import java.net.SocketException;
import java.net.URLEncoder;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;


public class MyOkHttpUtil {
    public static int ConnectTimeout = 30; //网络连接超时时间 (单位:秒)
    public static int WriteTimeout = 60; //写超时时间 (单位:秒)
    public static int ReadTimeout = 60; //读超时时间 (单位:秒)

    private OkHttpClient okHttpClient;


    /**
     * 私有的构造函数
     */
    private MyOkHttpUtil(){
        okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(ConnectTimeout, TimeUnit.SECONDS)
                .writeTimeout(WriteTimeout, TimeUnit.SECONDS)
                .readTimeout(ReadTimeout, TimeUnit.SECONDS)
                .retryOnConnectionFailure(false)
                .build();

    }

    /**
     * 获取单例的的方法
     */
    public static MyOkHttpUtil getInstance(){
        return MyOkHttpUtil.MyOkHttpUtilSingletonHolder.instance;
    }

    /**
     * 内部类的方式实现单例模式
     * 延迟加载，减少内存开销
     *
     */
    private static class MyOkHttpUtilSingletonHolder {
        private static MyOkHttpUtil instance = new MyOkHttpUtil();
    }






    /************************************** Okhttp请求 ************************************/
    /**
     * Get请求
     * */
    public void okHttpGet(Activity activity, String url, String requestTag, Map<String, Object> params, MyOkHttpCallBack listener) {
        //1.参数拼接
        try{
            String paramStr = "";
            for (String key : params.keySet()) {
                if (params.get(key) != null) {
                    paramStr = paramStr.concat(key + "=" + URLEncoder.encode(params.get(key).toString(), "UTF-8") + "&");
                }
            }
            if(paramStr.length() > 0) {
                paramStr = paramStr.substring(0, paramStr.length() - 1);
                url = url + "?" + paramStr;
            }
        }
        catch (Exception e) {
            Log.d("MySelf", "Exception");
            listener.onError(e.getMessage());
        }


        //2.构造一个Request对象, 参数最起码有个url (当然你可以通过Request.Builder设置更多的参数比如：header、method等。)
        final Request request = new Request.Builder()
                .url(url)
                .header("Connection", "close")
                .tag(requestTag)
                .build();
        //3.
        getResponse(activity, request, requestTag, listener);
    }


    /**
     * Post请求一.  (请求体的Content-Type 是 application/x-www-form-urlencoded)
     * */
    public void okHttpPostByFormEncoding(Activity activity, String url, String requestTag,  Map<String, Object> paramsMap, MyOkHttpCallBack listener) {
        //1.构建请求体 -- 格式为：key1=value1&key2=value2
        FormBody.Builder formBuilder = new FormBody.Builder();
        for (String key : paramsMap.keySet()) {
            if (paramsMap.get(key) == null) {
                continue;
            }
            formBuilder.add(key, paramsMap.get(key).toString());
        }
        RequestBody body = formBuilder.build();


        //2.构造一个Request对象，参数最起码有个url，
        //当然你可以通过Request.Builder设置更多的参数比如：header、method等。
        final Request request = new Request.Builder()
                .url(url)
                .header("Connection", "close")
                .tag(requestTag)
                .post(body)
                .build();
        //3.
        getResponse(activity, request, requestTag, listener);
    }


    /**
     * Post请求二.  (请求体的Content-Type 是 application/json)
     * */
    public void okHttpPostByJson(Activity activity, String url, String requestTag,  Map<String, Object> paramsMap, MyOkHttpCallBack listener) {
        //1.构建请求体
        //Map转Json字符串
        Gson gson = new Gson();
        String jsonStr = gson.toJson(paramsMap);
        Log.d("MySelf", "jsonStr: " + jsonStr);
        //
        MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        RequestBody body = RequestBody.create(JSON, jsonStr);


        //2.构造一个Request对象，参数最起码有个url，
        //当然你可以通过Request.Builder设置更多的参数比如：header、method等。
        final Request request = new Request.Builder()
                .url(url)
                .header("Connection", "close")
                .tag(requestTag)
                .post(body)
                .build();
        //3.
        getResponse(activity, request, requestTag, listener);
    }


    /**
     * Post请求三.  (请求体的Content-Type 是 multipart/form-data)
     * */
    public void okHttpPostByFormData(Activity activity, String url, String requestTag,  Map<String, Object> paramsMap, MyOkHttpCallBack listener) {
        //1.构建请求体
        MultipartBody.Builder formDataBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);
        for (String key : paramsMap.keySet()) {
            if (paramsMap.get(key) == null) {
                continue;
            }
            formDataBuilder.addFormDataPart(key, paramsMap.get(key).toString());
        }
        RequestBody body = formDataBuilder.build();


        //2.构造一个Request对象，参数最起码有个url，
        //当然你可以通过Request.Builder设置更多的参数比如：header、method等。
        final Request request = new Request.Builder()
                .url(url)
                .header("Connection", "close")
                .tag(requestTag)
                .post(body)
                .build();
        //3.
        getResponse(activity, request, requestTag, listener);
    }



    /** OkHttp请求的整个流程 **/
    public void getResponse(final Activity activity, Request request, final String requestTag, final MyOkHttpCallBack listener) {
        try {
            //1.取消基于该Tag标签的请求
            cancelTag(requestTag);

            //2.创建okHttpClient
            OkHttpClient mOkHttpClient = this.okHttpClient;

            //3.通过Request对象去构造一个Call对象
            //类似于将你的请求封装成了任务,既然是任务,就会有execute()和cancel()等方法
            Call call = mOkHttpClient.newCall(request);

            //4.以异步的方式去执行请求，所以我们调用的是call.enqueue, 将call加入调度队列
            //然后等待任务执行完成, 我们在Callback中可得到结果
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    AppLogger.d("", "(tag:" + requestTag  + ")" + "请求失败返回的数据：" + e.getClass().getName() + "  " + e.getMessage());
                    /* 异常类型有：
                       自己主动取消请求的错误是
                       java.net.SocketException: Socket closed
                       超时的错误是
                       java.net.SocketTimeoutException
                       网络出错的错误是
                       java.net.ConnectException: Failed to connect to xxxxx
                       java.net.UnknownHostException: Unable to resolve host "xxxxxxx": No address associated with hostname
                    */
                    if(e.toString().contains("closed")) {
                        //如果是主动取消请求的情况下
                    }else{
                        //其他情况下
                        listener.onError(e.getMessage());
                    }
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    if (response.isSuccessful()) {
                        final String responseJSON = response.body().string();
                        AppLogger.d("", "(tag:" + requestTag  + ")" + "请求成功返回的数据：\n" + responseJSON);
                        //因为OKHttp异步请求回调不是在主线程(UI线程)，所以如果你希望再次操作控件及更新界面信息，还是需要使用handler等
                        activity.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                listener.onSuccess(responseJSON);
                            }
                        });
                    }
                    else {
                        AppLogger.d("", "(tag:" + requestTag  + ")" + "响应状态码：" + response.code());
                        listener.onError("响应状态码: " + response.code());
                    }
                }
            });
        }
        catch (Exception exception) {
            AppLogger.d("", "(tag:" + requestTag  + ")" +"请求流程中抛异常：" + exception.getMessage());
            listener.onError(exception.getMessage());
        }
    }






    /************************************** Okhttp取消请求 ************************************/
    /**
     * 根据Tag取消请求
     * */
    public void cancelTag(Object tag) {
        if (tag == null) return;
        for(Call call : okHttpClient.dispatcher().queuedCalls()){ //正在排队的Call
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
        for (Call call : okHttpClient.dispatcher().runningCalls()) { //执行中的Call
            if (tag.equals(call.request().tag())) {
                call.cancel();
            }
        }
    }


    /**
     * 取消所有请求
     * */
    public void cancelAll() {
        for (Call call : okHttpClient.dispatcher().queuedCalls()) {
            call.cancel();
        }
        for (Call call : okHttpClient.dispatcher().runningCalls()) {
            call.cancel();
        }
    }




















    /**
     * 处理接口返回结果
     *
     * @param context
     *            上下文
     * @param resultMap
     *            请求接口返回的map
     * @return 如果code为10000，返回true; 否则返回false
     */
//    public static boolean analyseResponResult(Context context, Map<String, Object> resultMap) {
//        //1.判读code
//        String codeStr = CommonUtils.mapStringValueEmptyDeal(resultMap, "code");
//        if (! codeStr.isEmpty()) {
//            int code = Double.valueOf(codeStr).intValue();//字符串转int("200.0" 转int 200)
//            if (code == ResponseCode_SUCC) {
//                return true;
//            }
//            else {
//                if (code==ResponseCode_WaitUserPay || code==ResponseCode_NotAipayCode || code==ResponseCode_MemberCodeNotExist || code==ResponseCode_OrderPayed) {
//                    return false;
//                }
//
//                String message = CommonUtils.mapStringValueEmptyDeal(resultMap, "message");
//                if (message.isEmpty()){
//                    message = "操作失败";
//                }
//
//                CommonUtils.showToastAtCenter(context, message);
//            }
//        }
//
//        return false;
//    };

}
